--[[
    雪月框架    同步模块    v1.3

    新增    数据类型还原
            每个参数多花费一字节记录变量类型，解析数据包时再还原出来，方便直接调用

    依赖模块/函数特别说明
        string.split(str, s) 分割字符串

    雪月灬雪歌  2022/10/3  05:40
]]

local DzSyncData                = japi.DzSyncData
local DzTriggerRegisterSyncData = japi.DzTriggerRegisterSyncData
local DzGetTriggerSyncData      = japi.DzGetTriggerSyncData

local math_type = math.type
local type = type
local assert = assert
local traceback = debug.traceback
local table_concat = table.concat
local setmetatable = setmetatable
local tonumber = tonumber
local tostring = tostring


---@class sync_data
local sync_data = {
    type = 'sync_data',
    __mode = 'k',
}
---数据格式化 将不同数据类型的数据转换为字符串
local map_dataFormat = {
    number = function (value)
        --此处不会有nil值进入
        local tp = math_type( value )
        if tp == 'integer' then
            value = 'i' .. value
        else
            value =  'f' .. value
        end
        return value
    end,
    string = function (value)
        return 's' .. value
    end,
    boolean = function (value)
        return value and 'b1' or 'b0'
    end,
    ['nil'] = function (value)
        return 'n'
    end,
}
---数据解析: 传入字符串数据 转成对应数据类型数据 传出
local map_dataParser = {
    i = function (value)
        return math.floor( tonumber(value) )
    end,
    f = function (value)
        return tonumber(value) * 1.00
    end,
    s = function (value)
        return value
    end,
    b = function (value)
        return value == '0' and false or true
    end,
    n = function (_)
        return nil
    end,

}

sync_data.__index = sync_data

sync_data.__call = function(self)
    local data = {}
    local func

    data[1] = self[1]
    local idx = 1

    for i = 2, #self, 1 do
        idx = idx + 1
        func = map_dataFormat[ type(self[i]) ]
        if func then
            data[idx] = func( self[i] ) 
        else
            print('------')
            print(self[i])
            print('------')
            assert(false, traceback( '未知数据类型!' ))
        end

    end

	return table_concat(data, "&")
end
--sync class
sync = setmetatable({},{
    type = 'class',
    class = 'sync',
})

local __callback = {}

--中心分发器传参用
local package         = setmetatable( {}, sync )
local SYNC_SYSTEM_TAG = 'XG_SYNC'

--生成同步数据包
---@param ... any 任意个数据，但注意 如果添加的是一张表，只会检索一层表
---@return sync_data 返回一个同步数据包
function sync:new(...)

    local t = setmetatable
    (
        {
            [0] = 1,  --count
            [1] = "", --默认同步标签占位
        }
        ,sync_data
    )

    t:Add(...)
    return t
end


---加载同步的数据包
---@alias dataType string|number|boolean|nil
---@return table<int,dataType>
function sync:load()
	return package
end


--注册同步回调[]
---@param tag string 回调标签
---@param func function 回调函数
function sync:callback(tag, func)
    assert( type(tag) == 'string' and type(func) == 'function', traceback('参数类型错误') )
    if not __callback [tag] then
        __callback [tag] = { [0] = 1, func }
    else
        local idx = __callback [tag] [0] + 1
        __callback [tag] [0] = idx
        __callback [tag] [idx] = func
    end
    return func
end



--往同步数据包内添加数据
---@param self sync_data
---@param ... any 任意个数据，但注意 如果添加的是一张表，只会检索一层表
---@return self
function sync_data:Add(...)
	local d = { ... }
    local count = self[0]

	for i=1,#d do

		local p = type(d[i])
		if p == 'nil' then
		elseif p == 'string' then
            count = count + 1
			self[count] = d[i]
		elseif p == 'table' then
			for j=1,#d[i] do
                count = count + 1
			    self[count] = tostring(d[i][j])
			end
		else
			count = count + 1
			self[count] = d[i]
		end

	end

    self[0] = count
    --方便连续元方法
    return self
end


---发送同步数据包
---@param self sync_data
---@param tag string 同步标签，你需要使用sync(class)注册一个同步回调
function sync_data:Send(tag)
    self[1] = tag
	DzSyncData( SYNC_SYSTEM_TAG, self( ) )
end

--@private
--模块中心分发器

local trg  = cj.CreateTrigger() --同步模块中心分发器
DzTriggerRegisterSyncData(trg, SYNC_SYSTEM_TAG, false)
local function action()
    --package可用于传参 回调中使用 sync:load() 可载入同步数据包
    package = ( DzGetTriggerSyncData() or '' ):split( "&" )
    local tag = package [ 1 ] or ''

    local data = {}

    local idx = 0

    --跳过1个数据：同步标签
    local i = 1

    while true do

        i = i + 1
        local currentPackage = package[i]

        if not currentPackage then
            break
        end

        idx = idx + 1

        local packageType = currentPackage:sub(1,1)

        --数据解析
        local parser = map_dataParser[ packageType ]
        if parser then
            data[ idx ] = parser( currentPackage:sub(2) )
        else
            data[ idx ] = currentPackage:sub(2)
            print( "未知的同步数据类型:" , data[ idx ] )
        end

    end

    package = data

    setmetatable( package, sync_data )

    local callbacks = __callback[ tag ]
    if not callbacks then
        return
    end
    idx = 0
    while true do
        idx = idx + 1
        local callback = callbacks[idx]
        if not callback then
            break
        end
        callback ( )
    end

end
cj.TriggerAddAction( trg, action )
